/*
 * 人员迁移 - 人员数据迁移定义
 * 
 * 主要功能：
 * - 定义人员数据的数据库迁移
 * - 创建人员内容类型和部件
 * - 演示内容类型迁移的使用
 * - 提供内容类型初始化功能
 */

using Lombiq.TrainingDemo.Indexes;
using Lombiq.TrainingDemo.Models;
using OrchardCore.ContentFields.Fields;
using OrchardCore.ContentFields.Settings;
using OrchardCore.ContentManagement.Metadata;
using OrchardCore.ContentManagement.Metadata.Builders;
using OrchardCore.ContentManagement.Metadata.Settings;
using OrchardCore.Data.Migration;
using System;
using System.Threading.Tasks;
using YesSql.Sql;
using static Lombiq.HelpfulLibraries.OrchardCore.Contents.ContentFieldEditorEnums;

namespace Lombiq.TrainingDemo.Migrations;

/// <summary>
/// 人员迁移 - 定义人员数据的数据库迁移
/// 
/// 主要用途：
/// - 定义人员数据的数据库迁移
 //* - 创建人员内容类型和部件
 //* - 演示内容类型迁移的使用
 //* - 提供内容类型初始化功能
 //* 
 //* 使用场景：
/// - 初始化人员内容类型
/// - 创建内容类型定义
/// - 配置内容部件和字段
/// - 创建数据库索引表
/// 
/// 设计原因：
/// - 为人员数据提供内容类型支持
/// - 实现内容类型的版本控制
/// - 支持内容类型的初始化和管理
/// - 提供可重复的内容类型设置
/// 
/// 设计模式：
/// - 迁移模式：继承DataMigration实现数据库迁移
/// - 版本模式：使用版本号管理迁移
/// - 内容模式：使用IContentDefinitionManager管理内容类型
/// - 类型模式：创建和配置内容类型定义
/// </summary>
// 这是另一个迁移文件，但专门用于人员相关操作，包括如何定义内容类型和配置内容部件。
// 不要忘记在服务提供程序中注册此类（请参阅Startup.cs）。您也可以使用我们Helpful Extensions模块的
// 代码生成功能生成此类迁移步骤，请查看：https://github.com/Lombiq/Helpful-Extensions
public sealed class PersonMigrations : DataMigration
{
    private readonly IContentDefinitionManager _contentDefinitionManager;

    /// <summary>
    /// 构造函数 - 注入内容定义管理器
    /// </summary>
    /// <param name="contentDefinitionManager">内容定义管理器</param>
    public PersonMigrations(IContentDefinitionManager contentDefinitionManager) => _contentDefinitionManager = contentDefinitionManager;

    /// <summary>
    /// 创建异步方法 - 创建人员内容类型和配置
    /// 
    /// 功能说明：
    /// - 配置PersonPart部件
    /// - 创建PersonPartIndex索引表
    /// - 创建PersonPage内容类型
    /// - 创建PersonWidget小部件
    /// 
    /// 配置内容：
    /// - 为PersonPart添加Biography字段
    /// - 创建PersonPartIndex索引表
    /// - 创建PersonPage内容类型
    /// - 创建PersonWidget小部件
    /// 
    /// 字段配置：
    /// - Biography字段：文本区域编辑器
    /// - 显示名称：Biography
    /// - 提示信息：Person's biography
    /// </summary>
    /// <returns>迁移版本号</returns>
    public async Task<int> CreateAsync()
    {
        // 现在您可以配置PersonPart。例如，您可以在这里添加内容字段（如前面提到的）。
        await _contentDefinitionManager.AlterPartDefinitionAsync(nameof(PersonPart), part => part
            // 每个字段都有自己的配置。在这里您将为其提供一个显示名称，并添加一些额外的设置，
            // 比如在编辑器中显示的提示。
            .WithField(nameof(PersonPart.Biography), field => field
                .OfType(nameof(TextField))
                .WithDisplayName("Biography")
                .WithEditor(TextFieldEditors.TextArea)
                .WithSettings(new TextFieldSettings
                {
                    Hint = "Person's biography",
                }))
        );

        // 这将为PersonPartIndex创建一个索引表，如BookMigrations文件中所述。
        await SchemaBuilder.CreateMapIndexTableAsync<PersonPartIndex>(table => table
            .Column<DateTime>(nameof(PersonPartIndex.BirthDateUtc))
            .Column<Handedness>(nameof(PersonPartIndex.Handedness))
            // 内容项ID始终是26个字符。
            .Column<string>(nameof(PersonPartIndex.ContentItemId), column => column.WithLength(26))
        );

        // 我们创建一个新的内容类型。注意，只有一个alter方法：如果类型不存在，这将创建类型，
        // 如果存在，则修改它。确保您了解什么是内容类型：
        // https://docs.orchardcore.net/en/latest/docs/glossary/#content-type
        // 内容类型的名称是任意的，但要选择一个有意义的名称。注意我们如何使用带有常量的类来存储类型名称，
        // 这样我们就可以防止危险的复制粘贴。
        await _contentDefinitionManager.AlterTypeDefinitionAsync(ContentTypes.PersonPage, type => type
            .Creatable()
            .Listable()
            // 我们通过指定其名称来附加部件。对于我们自己的部件，我们使用nameof()：这不是强制性的，
            // 但如果我们在开发过程中更改部件的名称，它会很有用。
            .WithPart(nameof(PersonPart))
        );

        // 我们甚至可以使用相同的内容部件创建一个小部件。小部件只是普通的内容类型，但Stereotype设置为"Widget"。
        // 您会注意到我们站点的配置在前端包含三个区域，您可以在其中添加小部件，以及两个层。在管理界面中查看它们！
        await _contentDefinitionManager.AlterTypeDefinitionAsync("PersonWidget", type => type
            .Stereotype("Widget")
            .WithPart(nameof(PersonPart))
        );

        return 1;
    }
}

// 下一站：Indexes/PersonPartIndex
